// -*-c++-*-

/*
 *Copyright:

 Copyright (C) Hiroki SHIMORA

 This code is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 3, or (at your option)
 any later version.

 This code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this code; see the file COPYING.  If not, write to
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

 *EndCopyright:
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "sample_field_evaluator.h"

#include "field_analyzer.h"
#include "simple_pass_checker.h"

#include <rcsc/player/player_evaluator.h>
#include <rcsc/common/server_param.h>
#include <rcsc/common/logger.h>
#include <rcsc/math_util.h>

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cfloat>
#include "strategy.h"
// #define DEBUG_PRINT

using namespace rcsc;
static const int VALID_PLAYER_THRESHOLD = 8;
// static std::ofstream action_log;


/*-------------------------------------------------------------------*/
/*!

 */
static double get_opponent_dist( const PredictState & state,const Vector2D & point, int opponent_additional_chase_time = 0,int valid_opponent_thr = -1 );
static double evaluate_state( const PredictState & state,const std::vector< ActionStatePair > & path, const WorldModel & wm);
static double calcBasicValue( const PredictState & state );
// TODO 这个要不要保留？
// static double check_path(const PredictState & state);
void out_put_log(const char * describle);
static double getFirstActionPenalty( const PredictState & first_state,const ActionStatePair & first_pair);
/*-------------------------------------------------------------------*/
/*!

 */
SampleFieldEvaluator::SampleFieldEvaluator()
{

}

/*-------------------------------------------------------------------*/
/*!

 */
SampleFieldEvaluator::~SampleFieldEvaluator()
{

}


/*-------------------------------------------------------------------*/
/*!

 */
double
SampleFieldEvaluator::operator()( const PredictState & state,
                                  const std::vector< ActionStatePair > & path,
                                  const WorldModel & wm ) const
{
    const double final_state_evaluation = evaluate_state( state,path,wm );
    return final_state_evaluation;
}
/*
 * 对进攻的基本评估，包括当前位置与目标位置的距离、角度以及目标位置的周围环境等因素
 */
static
double
get_opponent_dist( const PredictState & state,
                   const Vector2D & point,
                   int opponent_additional_chase_time,
                   int valid_opponent_thr)
{
//WangJunYang
//在调用函数时，初始化赋值opponent_additional_chase_time = 0,valid_opponent_thr = -1(务必)
    static const double MAX_DIST = 65535.0;

    double min_dist = MAX_DIST;

    for (int i = 0;i<state.theirPlayers().size();i++)
    {
        if ( (state.theirPlayers()[i])->goalie() ) continue;
        if ( (state.theirPlayers()[i])->ghostCount() >= 3 ) continue;

        if ( valid_opponent_thr != -1 )
        {
            if ( (state.theirPlayers()[i])->posCount() > valid_opponent_thr )
            {
                continue;
            }
        }

        double dist = (state.theirPlayers()[i])->pos().dist( point );
        dist -= ( bound( 0, (state.theirPlayers()[i])->posCount() - 2, 2 )
                  + opponent_additional_chase_time )
            * (state.theirPlayers()[i])->playerTypePtr()->realSpeedMax();

        if ( dist < min_dist )
        {
            min_dist = dist;
        }
    }

    return min_dist;
}
/***********************************************************************************************/
double evaluate_for_normal( const PredictState & state )
{
    const ServerParam & SP = ServerParam::i() ;
    double point = 0.0 , distRate = 0.8 ;
    double dist2Target = state.ball().pos().dist(state.self().pos());
    double dist2Goal = state.self().pos().dist( Vector2D(SP.pitchHalfLength() , 0.0) ) ;

    if( state.self().pos().x < state.ball().pos().x && state.ball().pos().x < 36.0 ){
        distRate = - 0.1 ;
    }

    point += dist2Target ;
    point += 100 - dist2Goal  ;
    return point ;
}

/// evaluation function
/// 评测的方法
///
/// \param state
/// \param path
/// \return evaluation value of world model 评测世界模型的价值
/// 多种情况讨论
/// 特殊情况：
/// 1.球在敌方的球门里
/// 2.球在我方的球门里
/// 3.球出了球场
/// 正常情况：
/// 1.设置基础的评测
/// 2.某些情况增益
/// 3.附加评估
///
///WangJunYang
///惩罚性评估：
///1.动作长度
///2.动作类型
///3.距离
static
double
evaluate_state( const PredictState& state, const std::vector< ActionStatePair >& path, const WorldModel & wm  )
{
    const ServerParam & SP = ServerParam::i();
    const AbstractPlayerObject * holder = state.ballHolder();   // 创建一个抽象球员对象
// if holder is invalid, return bad evaluation
// 如果holder是无效的，返回bad evaluation
    if ( ! holder ){
        return -1; 
    }

//    const int holder_unum = holder->unum();

// ball is in opponent goal
// 球在敌方的球门里
// 球的X坐标 大于 球场半长度-0.1
// 球的Y坐标绝对值 小于 球门半宽度+2.0
    if( state.ball().pos().x > + ( SP.pitchHalfLength() - 0.1 )
         && state.ball().pos().absY() < SP.goalHalfWidth() + 2.0 ){
        Line2D holder_ball(state.ball().pos(),holder->pos());   // 球和持球者的连线
        const double y=holder_ball.getY(ServerParam::i().pitchHalfLength());//连线和底线交点的y坐标


        /*
         * 判断错误的角落进球
         */
        if( state.getOpponentGoalie() != NULL ){// 如果对方守门员存在

            if( y > SP.goalHalfWidth() || y < -SP.goalHalfWidth() ){ // 这个角度球不会进

                if( holder->pos().dist(Vector2D(ServerParam::i().pitchHalfLength(),y)) < 8// 持球者与交点的距离小于8

                 && holder->pos().x > 48// 持球者的x坐标小于48

                 && state.getOpponentGoalie()->pos().x > holder->pos().x// 对方守门员x坐标比持球者大

                 && state.getOpponentGoalie()->pos().absY() > 6.00// 对方守门员y坐标绝对值大于6.02

                 && state.getOpponentGoalie()->pos().y * holder->pos().y > 0// 对方守门员y坐标与持球者y坐标一个符号

                 && state.getOpponentGoalie()->pos().dist
                    (Vector2D(ServerParam::i().pitchHalfLength(),y))< 1.5 )// 对方守门员与交点的距离小于1.5
                        {
                        return -1;
                        }
            }

            double goal_dist=holder_ball.dist(state.getOpponentGoalie()->pos());//和守门员的距离

            if( y > -SP.goalHalfWidth() && y < SP.goalHalfWidth() ){ // 这个角度球可能进

                if( state.getOpponentGoalie()->pos().x > 50// 对方守门员x坐标大于50

                 && state.getOpponentGoalie()->pos().dist
                        (Vector2D(ServerParam::i().pitchHalfLength(),y))<6 )//对方守门员与交点的距离小于6
                        {
                    return 1+goal_dist/100;
                }
            }
        }
        //std::sprintf( output_text, "special_5:0" );
        //out_put_log( output_text );
        return +1;
    }

// ball is in our goal
// 球在我方的球门里
// 球的X坐标 小于 -（球场半长度-0.1）
// 球的Y坐标绝对值 小于 球门半宽度
    if( state.ball().pos().x < - ( SP.pitchHalfLength() - 0.1 )
         && state.ball().pos().absY() < SP.goalHalfWidth() ){
        return 0.5;
    }

// out of pitch
// 球出了球场
// 球的X坐标的绝对值 大于 球场半长度
// 球的Y坐标的绝对值 大于 球场半宽度
    if( state.ball().pos().absX() > SP.pitchHalfLength()
         || state.ball().pos().absY() > SP.pitchHalfWidth() ){
        return -1;
    }

// opponent has ball
// 对方有球
    if( state.ballHolder()->side() != state.self().side() ){
        return -1;
    }

// set basic evaluation
// 设置基础的评测
    double point = calcBasicValue( state );

// add bonus for goal, free situation near offside line
// 越位线附近的自由状态，增加球门的分值
    if ( FieldAnalyzer::can_shoot_from
         ( holder->unum() == state.self().unum(),
           holder->pos(),
           state.getPlayerCont( new OpponentOrUnknownPlayerPredicate( state.ourSide() ) ),
           VALID_PLAYER_THRESHOLD ) )
    {
        point += 0.5;
    }
//
// 附加评估
//
        // point +=  check_path( state );

    return point;
}

/// 计算基础评估值
///
static
double calcBasicValue( const PredictState & state )
{
    // 基础分较大，附加分影响较小
    double point = state.ball().pos().x + ServerParam::i().pitchLength();
    // 如果离对方球门过近，加分
    point += std::max( 0.0,
                       40.0 - ServerParam::i().theirTeamGoalPos().dist( state.ball().pos() ) )/50;
    // 如果离我方球门过近，减分
    point -= std::max( 0.0,
                       40.0 - ServerParam::i().ourTeamGoalPos().dist( state.ball().pos() ))/50;
    //end*/
    return point;
}